#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUF_SIZE 4096
#define _FILE_OFFSET_BITS 64

void usage()
{
	printf("#################################################\n"
	       " Usage: \n"
	       "split-file <file> <num>\n"
	       "split-file -c <file1 file2 ...> \n\n"
	       "a small file split and concatenate for you :-)\n"
	       "zhaoxiaoqiang <zxq_yx_007@163.com>\n"
	       "#################################################\n"
	      );
}

int is_number(char *str) 
{
	char *p = str;
	while (*p) {
		if (! isdigit(*p))
			return 0;
		p++;
	}
	return 1;
}


void split_file(char **argv) 
{
	FILE *fp = fopen(argv[1], "r");
	FILE *nfp;
	off_t total, each, target, now, nread, nwrite;
	int num, times, left, rsize;
	char buf[BUF_SIZE];
	char new_file[512];
	if (fp == NULL) {
		fprintf(stderr, "Error: file '%s' do not exist!\n", argv[1]);
		exit(1);
	}
	fseeko(fp, 0, SEEK_END);
	total = ftello(fp);
	fseeko(fp, 0, SEEK_SET);
	num = atoi(argv[2]);
	each = (total + num - 1) / num;
	printf("total file size is %ld\n", total);
	times = 1;
	now = 0;

	while(times <= num) {
		sprintf(new_file, "%s--part--%ld", argv[1], times);
		nfp = fopen(new_file, "w");
		if (nfp == NULL) {
			fprintf(stderr, "Error: can not create file '%s'!\n", new_file);
			exit(1);
		}
		if (now + each < total)
			target = now + each;
		else 
			target = total;
		printf("writing %s (%ld - %ld)\n", new_file, now + 1, target);
		while(now < target) {
			left = target - now;
			rsize = left < BUF_SIZE ? left : BUF_SIZE;
			if ((nread = fread(buf, 1, rsize, fp)) < 0) {
				fprintf(stderr, "Error: can not read file '%s'!\n", argv[1]);
				exit(1);
			}

			if ((nwrite = fwrite(buf, 1, rsize, nfp)) < 0) {
				fprintf(stderr, "Error: can not read write to '%s'!\n", new_file);
				exit(1);
			}
			now += nwrite;
		}
		fclose(nfp);
		times++;
	} 
	fclose(fp);
	printf("Done!\n");
}

void merge_file(int argc, char **argv)
{
	int num = argc - 2, times;
	char file[512];
	FILE *ofp, *nfp;
	char *p;
	off_t total, target, now, nread, nwrite;
	int left, rsize;
	char buf[BUF_SIZE];
	strcpy(file, argv[2]);
	p = strstr(file, "--part--");
	if (p == NULL) {
		fprintf(stderr, "Error: '%s' is not a valid part file!\n",argv[2]);
		exit(1);
	}
	*p = '\0';
	printf("out put file is %s\n", file);
	nfp = fopen(file, "w");
	if (nfp == NULL) {
		fprintf(stderr, "Error: can not create file '%s'!\n", file);
		exit(1);
	}

	times = 1;
	total = 0;
	while( times <= num) {
		ofp = fopen(argv[1 + times], "r");
		if (ofp == NULL) {
			fprintf(stderr, "Error: can not read file '%s'\n", argv[1 + times]);
			exit(1);
		}
		fseeko(ofp, 0, SEEK_END);
		target = ftello(ofp);
		fseeko(ofp, 0, SEEK_SET);
		printf("merging file '%s' (%ld - %ld)\n", argv[1 + times], total + 1, total + target);
		now = 0;
		while (now  <  target) {
			left = target - now;
			rsize = left < BUF_SIZE ? left : BUF_SIZE;
			if ((nread = fread(buf, 1, rsize, ofp)) < 0) {
				fprintf(stderr, "Error: can not read file '%s'\n", argv[1 + times]);
				exit(1);
			}
			
			if ((nwrite = fwrite(buf, 1, rsize, nfp)) < 0) {
				fprintf(stderr, "Error: can not write file '%s'\n", file);
				exit(1);
			}
			now += nwrite;
		}

		total += target;
		fclose(ofp);
		times++;
	}
	fclose(nfp);
	printf("wrote file '%s', size %ld\n", file, total);
}


int main(int argc, char **argv)
{
	if (argc < 3) {
		usage();
		return 0;
	}

	if (!strcmp(argv[1], "-c")) {
		merge_file(argc, argv);
	}
	else if (!strcmp(argv[1], "-")) {
		fprintf(stderr, "Error: invalid argument '%s'!\n", argv[1]);
		exit(1);
	}
	else if (is_number(argv[2])){
		split_file(argv);
	}
	else {
		fprintf(stderr, "Error: invalid argument '%s'!\n", argv[2]);
		exit(1);
	}
}
